/*
* Conditions Of Use
*
* This software was developed by employees of the Sigmatrix(Beijing) Corporation.
* This software is provided by sigmatrix as a service and is expressly
* provided "AS IS."  Sigmatrix MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
* AND DATA ACCURACY.  Sigmatrix does not warrant or make any representations
* regarding the use of the software or the results thereof, including but
* not limited to the correctness, accuracy, reliability or usefulness of
* the software.
*
* Permission to use this software is contingent upon your acceptance
* of the terms of this agreement.
*
*/
package com.sigmatrix.h5.web.controller;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.sigmatrix.h5.dto.OutStorageData;
import com.sigmatrix.h5.entity.SyncTask;
import com.sigmatrix.h5.enums.OutStorageStatusEnum;
import com.sigmatrix.h5.enums.ResponseEnum;
import com.sigmatrix.h5.enums.SyncTaskTypeEnum;
import com.sigmatrix.h5.exception.ServiceException;
import com.sigmatrix.h5.page.PageBean;
import com.sigmatrix.h5.response.Response;
import com.sigmatrix.h5.service.OutStorageService;
import com.sigmatrix.h5.service.SyncTaskService;
import com.sigmatrix.h5.utils.Cons;
import com.sigmatrix.h5.utils.ThreadPool;
import com.sigmatrix.h5.utils.VerifyUtil;
import com.sigmatrix.h5.web.controller.common.BaseController;
import com.sigmatrix.h5.web.vo.BaseOutStorageVo;
import com.sigmatrix.h5.web.vo.OutStorageVo;
import com.sigmatrix.h5.web.vo.SyncTaskVo;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;

/**
 *@ClassName: OutStorageController
 *@Description: 出库控制器
 *@author youjun
 *@date 2017年6月22日 下午7:26:21
 */
@Api(tags="出库相关接口")
@RestController
@RequestMapping("/app/outstorage")
public class OutStorageController extends BaseController {
	
	/**logger record*/
	private static final Logger LOGGER = LoggerFactory.getLogger(OutStorageController.class);
	
	/**出库单业务层接口*/
	@Autowired
	private transient OutStorageService outStorageService;
	
	/**异步任务业务层接口*/
	@Autowired
	private transient SyncTaskService syncTaskService;
	
	/**
	 *@Title: getPageList
	 *@Description: 出库单据分页查询接口
	 *@return Response
	 *@author youjun
	 *@date 2017年7月8日 上午10:44:23
	 *@param reqeust
	 *@param outStorageVo
	 *@param result
	 *@return
	 */
	@ApiOperation(value="出库单据分页查询接口", notes="根据具体的出库单类型分页查询出库单据")
	@ApiImplicitParams({
		@ApiImplicitParam(dataType="OutStorageVo", name="outStorageVo", value="出库单信息", required=true, paramType="body")
	})
	@PostMapping("/pagelist")
	public Response getPageList(final HttpServletRequest reqeust, @Valid @RequestBody final OutStorageVo outStorageVo, 
			final BindingResult result) {
		
		final String channelType = outStorageService.getChannelTypeDesc(outStorageVo);
		try{
			LOGGER.info("{}出库单据分页查询接口", channelType);
			LOGGER.info("查询的参数为:{}", JSONObject.toJSONString(outStorageVo));
			final Response validateResponse = validateParams(outStorageVo);
			if(validateResponse.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
				return validateResponse;
			}
			if (result.hasErrors()) {
				final String errInfo = result.getAllErrors().get(0).getDefaultMessage();
				LOGGER.error("{}出库单据分页查询接口参数验证失败{}", channelType, errInfo);
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, errInfo);
			}
			final PageBean<OutStorageData> pageBean = new PageBean<OutStorageData>(outStorageVo.getPageNo(), outStorageVo.getPageSize());
			final Response resultResponse = outStorageService.findListByPage(pageBean , outStorageVo, false);
			LOGGER.info("{}出库单据分页查询接口,返回的结果:{}", channelType, JSONObject.toJSONString(resultResponse));
			return resultResponse;
		}catch(Exception e) {
			LOGGER.error("{}出库单据分页查询接口失败", channelType, e);
			return new Response(ResponseEnum.EXCEPTION);
		}
	}
	
	/**
	 *@Title: validateParams
	 *@Description: TODO()
	 *@return Response
	 *@author youjun
	 *@date 2017年7月14日 下午2:39:50
	 *@param outStorageVo
	 *@return
	 */
	private Response validateParams(OutStorageVo outStorageVo) {
		final Response validateBasic = validateBasicParams(outStorageVo, true);
		if(validateBasic.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
			return validateBasic;
		}
		// 验证日期
		final String createTimeStart = outStorageVo.getCreateTimeStart();
		final String createTimeEnd = outStorageVo.getCreateTimeEnd();
		if(StringUtils.isNotBlank(createTimeStart)) {
			if(!VerifyUtil.isValidDate(createTimeStart)) {
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "创建时间开始段格式有误");
			}
		}
		if(StringUtils.isNotBlank(createTimeEnd)) {
			if(!VerifyUtil.isValidDate(createTimeEnd)) {
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "创建时间结束段格式有误");
			}
		}
		return new Response(ResponseEnum.SUCCESS);
	}

	/**
	 *@Title: getOutStorageList
	 *@Description: 获取出库单列表接口
	 *@return Response
	 *@author youjun
	 *@date 2017年6月26日 下午5:47:29
	 *@param reqeust
	 *@param outStorageVo
	 *@return
	 */
	@ApiOperation(value="获得出库单列表接口", notes="根据出库单类型(销售出库、返工出库、调拨出库、其他出库)获得相应的出库单列表")
	@ApiImplicitParams({
		@ApiImplicitParam(dataType="OutStorageVo", name="outStorageVo", value="出库单信息", required=true, paramType="body")
	})
	@PostMapping("/list")
	public Response getOutStorageList(final HttpServletRequest reqeust, @Valid @RequestBody final OutStorageVo outStorageVo, 
			final BindingResult result) {
		LOGGER.info("调取出库单列表开始...");
		try {
			if (result.hasErrors()) {
				final String errInfo = result.getAllErrors().get(0).getDefaultMessage();
				LOGGER.error("获取出库单列表接口参数验证失败{}", errInfo);
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, errInfo);
			}
			LOGGER.info("请求参数为:{}", JSONObject.toJSONString(outStorageVo));
			// 只返回已审核状态的给手持机
			outStorageVo.setStatus(OutStorageStatusEnum.SPECIAL_FOR_PDA_SYNC_LIST.getId().shortValue());
			return outStorageService.getOutStorageList(outStorageVo, true);
		} catch (ServiceException e) {
			LOGGER.error("调取出库单列表接口异常", e);
			return new Response(ResponseEnum.EXCEPTION);
		}
	}
	
	/**
	 *@Title: saveOutStorage
	 *@Description: 新增出库单接口
	 *@return Response
	 *@author youjun
	 *@date 2017年7月6日 上午11:01:28
	 *@param reqeust
	 *@param outStorageVo
	 *@param result
	 *@return
	 */
	@ApiOperation(value="新增出库单接口", notes="根据出库单类型(销售出库、返工出库、调拨出库、其他出库)保存相应的出库单")
	@ApiImplicitParams({
		@ApiImplicitParam(dataType="OutStorageVo", name="outStorageVo", value="出库单信息", required=true, paramType="body")
	})
	@PostMapping("/save")
	public Response saveOutStorage(final HttpServletRequest reqeust, @Valid @RequestBody final OutStorageVo outStorageVo, 
			final BindingResult result) {
		
		final String channelTypeDesc = outStorageService.getChannelTypeDesc(outStorageVo);
		LOGGER.info("新增{}出库单接口开始", channelTypeDesc);
		try {
			LOGGER.info("请求参数为:{}", JSONObject.toJSONString(outStorageVo));
			if (result.hasErrors()) {
				final String errInfo = result.getAllErrors().get(0).getDefaultMessage();
				LOGGER.error("新增{}出库单列表接口参数验证失败{}", channelTypeDesc, errInfo);
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, errInfo);
			}
			final Response resultResponse = outStorageService.save(outStorageVo);
			LOGGER.info("新增{}出库单接口返回结果{}", channelTypeDesc, JSONObject.toJSONString(resultResponse));
			return resultResponse;
		}catch(Exception e) {
			LOGGER.error("新增{}出库单接口失败", channelTypeDesc, e);
			return new Response(ResponseEnum.EXCEPTION);
		}
	}
	
	/**
	 *@Title: uploadOutStorage
	 *@Description: 上传出库单操作
	 *@return Response
	 *@author youjun
	 *@date 2017年8月3日 下午10:13:54
	 *@param reqeust
	 *@param outStorageVo
	 *@param result
	 *@return
	 */
	@ApiOperation(value="上传出库单操作", notes="上传出库单操作")
	@ApiImplicitParam(dataType="OutStorageVo", name="outStorageVo", value="出库单信息", required=true, paramType="body")
	@PostMapping(value="/upload")
	public Response uploadOutStorage(final HttpServletRequest reqeust, @Valid @RequestBody final OutStorageVo outStorageVo, 
			final BindingResult result) {
		
		final String channelTypeDesc = outStorageService.getChannelTypeDesc(outStorageVo);
		LOGGER.info("上传{}出库单接口开始", channelTypeDesc);
		try {
			LOGGER.info("请求参数为:{}", JSONObject.toJSONString(outStorageVo));
			if (result.hasErrors()) {
				final String errInfo = result.getAllErrors().get(0).getDefaultMessage();
				LOGGER.error("上传{}出库单列表接口参数验证失败{}", channelTypeDesc, errInfo);
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, errInfo);
			}
			
			final String enterpriseCode = outStorageVo.getEnterpriseCode();
			SyncTaskVo syncTaskVo = new SyncTaskVo();
			syncTaskVo.setCreateTime(new Date());
			syncTaskVo.setEnterpriseCode(enterpriseCode );
			syncTaskVo.setRequestParams(JSONObject.toJSONString(outStorageVo));
			syncTaskVo.setStatus(Cons.SYNC_TASK_STATUS_NO_HANDLE); // 待处理
			syncTaskVo.setType(getType(outStorageVo));
			final int syncTaskId = syncTaskService.save(syncTaskVo);
			
			// 异步处理
			outStorageVo.setSyncTaskId(syncTaskId);
//			outStorageService.upload(outStorageVo);
			
			ThreadPool.executor.submit(() -> {
				try {
					outStorageService.upload(outStorageVo);
				} catch(Exception e) {
					SyncTask updateSyncTask = new SyncTask();
					updateSyncTask.setIsSuccess(Cons.SYNC_TASK_FAIL);
					updateSyncTask.setResponseCode(Cons.RESPONSE_CODE_DATA_EXCEPTION+"");
					updateSyncTask.setResponseMsg(e.getMessage());
//					updateSyncTask.setResponseResult();
					updateSyncTask.setTypeSign(outStorageVo.getOrderCode());
					updateSyncTask.setStatus(Cons.SYNC_TASK_STATUS_HANDLE_FINISH); // 处理完成
					try {
						syncTaskService.updateByCondition(enterpriseCode, syncTaskId, updateSyncTask);
					} catch (ServiceException e1) {
						LOGGER.error("异步处理失败", e);
					}
				}
			});
			
			Map<String, Object> resultMap = new HashMap<String, Object>();
			resultMap.put("syncTaskId", syncTaskId);
			final Response resultResponse = new Response(ResponseEnum.SUCCESS, resultMap);
			LOGGER.info("上传{}出库单接口返回结果{}", channelTypeDesc, JSONObject.toJSONString(resultResponse));
			return resultResponse;
		}catch(Exception e) {
			LOGGER.error("上传{}出库单接口失败", channelTypeDesc, e);
			return new Response(ResponseEnum.EXCEPTION);
		}
	}

	private short getType(final OutStorageVo outStorageVo) {
		short type = 0;
		if (outStorageVo.getChannelType() == 1) {
			type = SyncTaskTypeEnum.OUT_STORAGE_CHANNEL_TYPE_SALES.getId().shortValue();
		}
		if (outStorageVo.getChannelType() == 2) {
			type = SyncTaskTypeEnum.OUT_STORAGE_CHANNEL_TYPE_REWORK.getId().shortValue();
		}
		if (outStorageVo.getChannelType() == 3) {
			type = SyncTaskTypeEnum.OUT_STORAGE_CHANNEL_TYPE_TRANSFERS.getId().shortValue();
		}
		if (outStorageVo.getChannelType() == 4) {
			type = SyncTaskTypeEnum.OUT_STORAGE_CHANNEL_TYPE_OTHER.getId().shortValue();
		}
		return type;
	}
	
	/**
	 *@Title: getOutStorageDetail
	 *@Description: 
	 *@return Response
	 *@author youjun
	 *@date 2017年7月8日 下午2:37:52
	 *@param request
	 *@param baseRequest
	 *@param result
	 *@return
	 */
	@ApiOperation(value="出库单单据详情", notes="根据单据ID获得出库单单据详情")
	@ApiImplicitParams({
		@ApiImplicitParam(dataType="BaseOutStorageVo", name="baseOutStorageVo", value="企业code、终端ID、出库单ID等信息", required=true, paramType="body")
	})
	@PostMapping("/detail")
	public Response getOutStorageDetail(final HttpServletRequest request, 
			@RequestBody final BaseOutStorageVo baseOutStorageVo) {
		
		try{
			LOGGER.info("获取出库单单据详情接口开始...");
			final Response validateResponse = validateBasicParams(baseOutStorageVo, true);
			if(validateResponse.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
				return validateResponse;
			}
			if(baseOutStorageVo.getOutStorageId()==null) {
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "出库单ID不能为空");
			}
			if(validateResponse.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
				return validateResponse;
			}
			final Response resultResponse = outStorageService.findById(baseOutStorageVo, baseOutStorageVo.getOutStorageId());
			LOGGER.info("获取出库单单据详情接口返回结果:{}", JSONObject.toJSONString(resultResponse));
			return resultResponse;
		}catch(Exception e){
			LOGGER.error("获取出库单单据详情接口失败", e);
			return new Response(ResponseEnum.EXCEPTION);
		}
	}
	
	/**
	 *@Title: close
	 *@Description: 关闭订单
	 *@return Response
	 *@author youjun
	 *@date 2017年8月23日 下午3:58:33
	 *@param request
	 *@param baseOutStorageVo
	 *@return
	 */
	@ApiOperation(value="关闭出库单", notes="根据单据ID关闭出库单")
	@ApiImplicitParams({
		@ApiImplicitParam(dataType="BaseOutStorageVo", name="baseOutStorageVo", value="企业code、终端ID、出库单ID等信息", required=true, paramType="body")
	})
	@PostMapping(value="/close")
	public Response close(final HttpServletRequest request, 
			@RequestBody final BaseOutStorageVo baseOutStorageVo) {
		
		try{
			LOGGER.info("关闭出库单单据接口开始...");
			final Response validateResponse = validateBasicParams(baseOutStorageVo, true);
			if(validateResponse.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
				return validateResponse;
			}
			if(baseOutStorageVo.getOutStorageId()==null) {
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "出库单ID不能为空");
			}
			if(validateResponse.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
				return validateResponse;
			}
			final Response resultResponse = outStorageService.colse(baseOutStorageVo);
			LOGGER.info("关闭出库单单据接口接口返回结果:{}", JSONObject.toJSONString(resultResponse));
			return resultResponse;
		}catch(Exception e){
			LOGGER.error("关闭出库单单据接口接口失败", e);
			return new Response(ResponseEnum.EXCEPTION);
		}
	}

}
